package com.hjm.job.handler;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hjm.common.core.constants.CacheConstants;
import com.hjm.common.core.constants.Constants;
import com.hjm.job.domain.exam.Exam;
import com.hjm.job.domain.exam.UserExamScore;
import com.hjm.job.domain.message.Message;
import com.hjm.job.domain.message.MessageText;
import com.hjm.job.domain.message.vo.MessageTextVO;
import com.hjm.job.domain.user.UserExam;
import com.hjm.job.mapper.exam.ExamMapper;
import com.hjm.job.mapper.exam.UserExamMapper;
import com.hjm.job.mapper.exam.UserSubmitMapper;
import com.hjm.job.mapper.message.MessageTextMapper;
import com.hjm.job.service.message.IMessageService;
import com.hjm.job.service.message.IMessageTextService;
import com.hjm.redis.service.RedisService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


@Slf4j
@Component
public class ExamXxlJob {

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    RedisService redisService;

    @Autowired
    UserSubmitMapper userSubmitMapper;

    @Autowired
    UserExamMapper userExamMapper;

    @Autowired
    MessageTextMapper messageMapper;

    @Autowired
    IMessageTextService messageTextService;

    @Autowired
    IMessageService messageService;

    @XxlJob("examListOrganizeHandler")
    public void examListOrganizeHandler() {
        log.info("*********examListOrganizeHandler********");
        //未完赛竞赛列表
        List<Exam> unFinishList = examMapper.selectList(new
                LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime,Exam::getEndTime)
                .gt(Exam::getEndTime, LocalDateTime.now())
                .eq(Exam::getStatus, Constants.TRUE)
                .orderByDesc(Exam::getCreateTime));
        refreshCache(unFinishList,CacheConstants.EXAM_NOT_STARTED_LIST);
        //历史竞赛列表

        List<Exam> historyExamList = examMapper.selectList(new
                LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle, Exam::getStartTime,Exam::getEndTime)
                .le(Exam::getEndTime, LocalDateTime.now())
                .eq(Exam::getStatus, Constants.TRUE)
                .orderByDesc(Exam::getCreateTime));
        refreshCache(historyExamList,CacheConstants.EXAM_HISTORY_LIST);
    }


    @XxlJob("examResultHandler")
    public void examResultHandler() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime minusDateTime = now.minusDays(1);
        // 获取到 昨天的竞赛列表
        List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .select(Exam::getExamId, Exam::getTitle)
                .eq(Exam::getStatus, Constants.TRUE)
                .ge(Exam::getEndTime, minusDateTime)
                .le(Exam::getEndTime, now));
        if (CollectionUtil.isEmpty(examList)) {
            return;
        }
        Set<Long> examIdSet = examList.stream().map(Exam::getExamId).collect(Collectors.toSet());
        List<UserExamScore> userScoreList = userSubmitMapper.selectUserScoreList(examIdSet);

        // 按照 examId 进行分组
        Map<Long, List<UserExamScore>> userScoreMap = userScoreList.stream().collect(Collectors.groupingBy(UserExamScore::getExamId));

        createMessage(examList, userScoreMap);
    }

    private void createMessage(List<Exam> examList, Map<Long, List<UserExamScore>> userScoreMap) {
        List<MessageText> messageTextList = new ArrayList<>();
        List<Message> messageList = new ArrayList<>();

        for (Exam exam : examList) {
            Long examId = exam.getExamId();
            // 拿到每一门竞赛 的每个用户的 成绩
            List<UserExamScore> userScoreList = userScoreMap.get(examId);
            int total = userScoreList.size();
            int examRank = 1;
            // 构建好消息
            for( UserExamScore userExamScore : userScoreList) {
                String msgtitle = exam.getTitle()+" 竞赛结果通知 : ";
                String msgContent = "恭喜你，你参加的 "+exam.getTitle()+" 竞赛,得分为"
                        +userExamScore.getScore()+"分，排名: 第 "+examRank+" 名(共 "+total+" 人)";
                // 存储 排名 消息到 数据库中
                MessageText messageText = new MessageText();
                messageText.setMessageTitle(msgtitle);
                messageText.setMessageContent(msgContent);
                messageText.setUserId(userExamScore.getUserId());
                messageText.setCreateBy(Constants.SYSTEM_USER_ID);
                messageTextList.add(messageText);

                Message message = new Message();
                message.setSendId(Constants.SYSTEM_USER_ID);
                message.setCreateBy(Constants.SYSTEM_USER_ID);
                message.setRecId(userExamScore.getUserId());

                messageList.add(message);

                userExamScore.setExamRank(examRank);

                UserExam userExam = new UserExam();
                BeanUtils.copyProperties(userExamScore, userExam);
                userExamMapper.update(userExam,
                        new LambdaQueryWrapper<UserExam>().
                                eq(UserExam::getExamId,examId).
                                eq(UserExam::getUserId,userExamScore.getUserId()));
                examRank++;
            }
            // 更新用户的 成绩 和 排名
//            userExamMapper.updateUserScoreAndRank(userScoreList);
            redisService.rightPushAll(getRankListKey(examId),userScoreList);
        }
        // 批量插入
        messageTextService.insertBatch(messageTextList);
        Map<String , MessageTextVO> messageTextVOMap = new HashMap<>();
        for(int i=0;i<messageTextList.size();i++){
            MessageText messageText = messageTextList.get(i);
            // 存储 排名 消息到 redis 中 m:d:+ textId --- messageTextVO
            MessageTextVO messageTextVO = new MessageTextVO();
            BeanUtils.copyProperties(messageText,messageTextVO);
            String msgDetailKey = getMsgDetailKey(messageText.getTextId());
            messageTextVOMap.put(msgDetailKey, messageTextVO);

            Message message = messageList.get(i);
            message.setSendId(Constants.SYSTEM_USER_ID);
            message.setTextId(messageText.getTextId());
        }
        redisService.multiSet(messageTextVOMap);
        messageService.insertBatch(messageList);

        // 根据 userId 进行分组
        Map<Long, List<Message>> userMsgMap = messageList.stream().collect(Collectors.groupingBy(Message::getRecId));
        Iterator<Map.Entry<Long, List<Message>>> iterator = userMsgMap.entrySet().iterator();
        while(iterator.hasNext()){
            Map.Entry<Long, List<Message>> entry = iterator.next();
            Long userId = entry.getKey();
            String userMsgListKey = getUserMsgListKey(userId);
            List<Long> userMsgTextList = entry.getValue().stream().map(Message::getTextId).toList();
            redisService.rightPushAll(userMsgListKey,userMsgTextList);
        }
    }

    public void refreshCache(List<Exam> examList,String examListKey) {

        if(CollectionUtil.isEmpty(examList)){
            redisService.deleteObject(examListKey);
            return ;
        }

        // examList 是从数据库中获取的数据，现在要同步到 redis 中去
        Map<String ,Exam> examMap =new HashMap<>();
        List<Long> examIdList =new ArrayList<>();
        for(Exam exam : examList){
            examMap.put(getDetailKey(exam.getExamId()),exam);   // 存竞赛信息
            examIdList.add(exam.getExamId());
        }
        redisService.multiSet(examMap);

        redisService.deleteObject(examListKey);                   // 删除之前存储的数据
        redisService.rightPushAll(examListKey,examIdList);        // 存储 比较全的数据
    }



    private String getDetailKey(Long examId) {
        return CacheConstants.EXAM_DETAIL+examId;
    }

    private String getUserMsgListKey(Long userId) {
        return CacheConstants.USER_MESSAGE_LIST + userId;
    }

    private String getMsgDetailKey(Long textId) {
        return CacheConstants.MESSAGE_DETAIL + textId;
    }
    private String getRankListKey(Long examId) {
        return CacheConstants.EXAM_RANK_LIST + examId;
    }
}
